import torch
from torch import nn
import torch.nn.functional as F

class MyAlexNet(nn.Module):
    def __init__(self):
        super(MyAlexNet, self).__init__()
        self.c1 = nn.Conv2d(in_channels=3, out_channels=48, kernel_size=11, stride=4, padding=2)
        self.ReLU = nn.ReLU()
        # 将卷积层的输出经过 ReLU 激活函数的变换，得到一个非线性的特征图。
        self.c2 = nn.Conv2d(in_channels=48, out_channels=128, kernel_size=5, stride=1, padding=2)
        # 这一层的作用是在前一层的基础上进一步提取图像的特征，增加模型的非线性拟合能力。
        self.s2 = nn.MaxPool2d(2)
        # 定义了一个最大池化层，用于将输入的特征图进行下采样操作，减少特征图的大小，并且增强模型对位置和尺度的不变性。
        self.c3 = nn.Conv2d(in_channels=128, out_channels=192, kernel_size=3, stride=1, padding=1)
        self.s3 = nn.MaxPool2d(2)
        self.c4 = nn.Conv2d(in_channels=192, out_channels=192, kernel_size=3, stride=1, padding=1)
        self.c5 = nn.Conv2d(in_channels=192, out_channels=128, kernel_size=3, stride=1, padding=1)
        # 这两个卷积层的作用是在“收窄”卷积网络，逐渐减小输出特征图的通道数，减少参数量，增加模型的效率和泛化能力。
        # 将输出通道从 192 降到了 128，这既减少了模型的参数数量，又提高了网络学习的鲁棒性和泛化性能。同时，也使得模型的计算开销更小，并降低了过拟合的风险。
        self.s5 = nn.MaxPool2d(kernel_size=3, stride=2)
        self.flatten = nn.Flatten()
        # 将输入张量展平成为一个一维向量。
        self.f6 = nn.Linear(4608, 2048)
        # 全连接层，输入维度为6*6*128=4608（batch_size），输出维度为2048
        self.f7 = nn.Linear(2048, 2048)
        self.f8 = nn.Linear(2048, 1000)
        self.f9 = nn.Linear(1000, 2)
        # 本问题是个二分类问题，所以输出维度为2，一个表示正类的概率，另一个表示负类的概率

    def forward(self, x):
        x = self.ReLU(self.c1(x))
        x = self.ReLU(self.c2(x))
        x = self.s2(x)
        x = self.ReLU(self.c3(x))
        x = self.s3(x)
        x = self.ReLU(self.c4(x))
        x = self.ReLU(self.c5(x))
        x = self.s5(x)
        x = self.flatten(x)
        x = self.f6(x)
        x = F.dropout(x, p=0.5)
        # Dropout 是一种正则化技术，用于在模型训练时随机地丢弃一部分神经元。避免模型对某些特定的神经元过分依赖，提高模型的泛化能力。
        # 0.5表示每个值在训练时候有50%几率被抛弃
        # Dropout 一般只在模型在训练时使用
        # 在测试时不使用。在测试时需要将该层的 Dropout 设置为不起作用，以确保模型的预测结果不会受到失活的影响。
        # 可以使用 model.eval() 将模型切换为测试模式，从而关闭 Dropout 层。
        x = self.f7(x)
        x = F.dropout(x, p=0.5)
        x = self.f8(x)
        x = F.dropout(x, p=0.5)
        x = self.f9(x)
        return x

if __name__ == '__mian__':
    x = torch.rand([1, 3, 224, 224])
    # 这段代码使用 PyTorch 库创建一个形状为 (1, 3, 224, 224) 的张量 x，并将其初始化为随机数。
    # 形状是 (1, 3, 224, 224)，其中 1 表示 mini-batch 的大小， 3 表示输入的通道数， 224 表示输入的高度和宽度。
    model = MyAlexNet()
    y = model(x)
    # 调用实例化的 MyAlexNet() 模型的 forward 方法，并传入输入张量 x 作为参数。模型的输出结果将保存在变量 y 中。







